package cn.openea.perpartner.expert.web.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.openea.perpartner.common.core.manager.AsyncManager;
import cn.openea.perpartner.common.core.text.Convert;
import cn.openea.perpartner.common.core.utils.Arith;
import cn.openea.perpartner.common.core.web.domain.AjaxResult;
import cn.openea.perpartner.expert.web.domain.dto.DeliveryDto;
import cn.openea.perpartner.expert.web.domain.dto.MsgDto;
import cn.openea.perpartner.expert.web.domain.dto.TimelineDto;
import cn.openea.perpartner.expert.web.domain.entity.Delivery;
import cn.openea.perpartner.expert.web.domain.entity.ExpertJob;
import cn.openea.perpartner.expert.web.mapper.DeliveryMapper;
import cn.openea.perpartner.expert.web.service.IDeliveryService;
import cn.openea.perpartner.expert.web.service.IExpertJobService;
import cn.openea.perpartner.expert.web.service.ISendMsgService;
import cn.openea.perpartner.expert.web.service.ITimelineService;
import cn.openea.perpartner.meily.web.entity.Todo;
import cn.openea.perpartner.meily.web.service.ITodoService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;

/**
 * 专家协作交付表(Delivery)表服务实现类
 *
 * @author Weird077
 * @since 2023-06-19 11:45:57
 */
@Slf4j
@Service("deliveryService")
public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> implements IDeliveryService {
    @Value("${sso.url}")
    private String ssoUri;
    @Value("${payment.order.authSalt}")
    private String authSalt;
    @Value("${payment.order.getTokenUrl}")
    private String getOrderSysTokenUrl;

    private JSONObject userInfo;
    @Resource
    private ITodoService todoService;
    @Resource
    private IExpertJobService expertJobService;
    @Resource
    private ISendMsgService sendMsgService;
    @Resource
    private ITimelineService timelineService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean partnerSubmitResult(DeliveryDto dto) {
        //1、更新待办状态
        todoService.updateToDoToDone(dto.getPartnerId(), dto.getTaskNumber());
        //2、更新付款状态和工作成果
        Delivery delivery = getById(dto.getDeliveryId());
        delivery.setPaymentStatus("验收中");
        delivery.setDeliveryTime(DateUtil.now());
        JSONArray jsonArray = JSON.parseArray(delivery.getTaskResultList());
        if (ObjectUtil.isNull(jsonArray)) {
            jsonArray = new JSONArray();
        }
        jsonArray.add(dto.getTaskResult());
        delivery.setTaskResultList(jsonArray.toJSONString());
        updateById(delivery);
        //3、获取返修次数
        int retryCount = Convert.toInt(delivery.getReturnNum());
        ExpertJob job = expertJobService.getByTaskNum(dto.getTaskNumber());
        //3、发送时间轴消息
        AsyncManager.me().execute(timelineService.partnerSubmitResult(TimelineDto.builder()
                .ticketNum(job.getTaskNum())
                .userId(dto.getPartnerId())
                .eventTitle(retryCount > 0 ? "第" + retryCount + "次返修" : "提交成果")
                .eventDetail(retryCount > 0 ? "第" + retryCount + "次返修已提交成果" : "已提交成果")
                .build()));
        //4、异步发送小程序消息通知
        AsyncManager.me().execute(sendMsgService.partnerSubmitResult(MsgDto.builder()
                .deliveryId(dto.getDeliveryId())
                .taskNum(job.getTaskNum())
                .userId(job.getCreateUser())
                .minAppUri("/pages_private_scene1/ExpertCooperate/UserAcceptance?taskNumber=" + dto.getTaskNumber() + "&deliveryId=" + dto.getDeliveryId())
                .partnerId(dto.getPartnerId())
                .build()));
        //4、发送待办给验收人
        return todoService.addToDoData(Todo.builder()
                .taskId(Convert.toStr(job.getJobId()))
                .subject(job.getSubject())
                .reqNumber(job.getTaskNum())
                .userId(job.getCreateUser())
                .startTime(DateUtil.now())
                .status("Current")
                .nodeName(retryCount > 0 ? "第" + retryCount + "次修改" : "验收成果")
                .prvUserId(dto.getPartnerId())
                .prvNickName(getUserNickName(dto.getPartnerId()))
                .prvUserAvatar(getUserAvatar(dto.getPartnerId()))
                .minAppUri("/pages_private_scene1/ExpertCooperate/UserAcceptance?taskNumber=" + dto.getTaskNumber() + "&deliveryId=" + dto.getDeliveryId())
                .build());
    }

    @Override
    public boolean userVerifyResult(DeliveryDto dto) {
        //1、更新待办状态
        todoService.updateToDoToDone(dto.getInitiatorId(), dto.getTaskNumber());
        //2、更新付款状态和任务状态
        Delivery delivery = getById(dto.getDeliveryId());
        delivery.setPaymentStatus("已验收");
        delivery.setPeriodStatus("已完成");
        delivery.setAcceptanceTime(DateUtil.now());
        delivery.setActualPrice(dto.getActualPrice());
        delivery.setSatisfiedDegree(dto.getSatisfiedDegree());
        delivery.setApprovalReasons(dto.getApprovalReasons());
        updateById(delivery);
        //3、发放佣金
        AsyncManager.me().execute(grantCommission(delivery));
        //4、启动下一期任务，
        ExpertJob job = expertJobService.getByTaskNum(dto.getTaskNumber());
        //5、取项目期数
        int count = job.getPaymentType().split(":").length;
        //6、取当前期数
        int sortNum = Convert.toInt(delivery.getSubTaskSortNum());
        //7、取返修次数
        int retryCount = Convert.toInt(delivery.getReturnNum());
        Todo todoData;
        TimelineDto timelineDto;
        MsgDto msgDto = MsgDto.builder()
                .taskNum(job.getTaskNum())
                .deliveryId(delivery.getDeliveryId())
                .userId(dto.getInitiatorId())
                .partnerId(dto.getPartnerId())
                .build();
        if (Arith.sub(count, sortNum) > 0) {
            //8、启动下一期任务
            JSONObject next = JSON.parseArray(job.getWorkContent()).getJSONObject(sortNum);
            delivery = Delivery.builder()
                    .taskNumber(job.getTaskNum())
                    .workSubject(job.getSubject())
                    .budget(job.getBudget())
                    .paymentType(job.getPaymentType())
                    .workEndDate(job.getDeliveryDate())
                    .partnerId(dto.getPartnerId())
                    .partnerName(dto.getPartnerName())
                    .initiatorId(dto.getInitiatorId())
                    .initiatorName(dto.getInitiatorName())
                    .totalPeriods(Convert.toStr(count))
                    .subTaskSortNum(Convert.toStr(sortNum + 1))
                    .contentAndRequire(next.getString("content"))
                    .deliveryDate(next.getString("subDate"))
                    .subTaskPrice(next.getString("brokerage"))
                    .build();
            save(delivery);
            todoData = Todo.builder()
                    .taskId(Convert.toStr(job.getJobId()))
                    .subject(job.getSubject())
                    .reqNumber(job.getTaskNum())
                    .userId(dto.getPartnerId())
                    .startTime(DateUtil.now())
                    .status("Current")
                    .nodeName("提交成果")
                    .prvUserId(dto.getInitiatorId())
                    .prvNickName(getUserNickName(dto.getInitiatorId()))
                    .prvUserAvatar(getUserAvatar(dto.getInitiatorId()))
                    .minAppUri("/pages_private_scene1/ExpertCooperate/partnerDelivery?taskNumber=" + dto.getTaskNumber() + "&deliveryId=" + delivery.getDeliveryId())
                    .build();
            timelineDto = TimelineDto.builder()
                    .userId(dto.getInitiatorId())
                    .ticketNum(job.getTaskNum())
                    .eventTitle(retryCount > 0 ? "第" + retryCount + "次返修" : "验收成果")
                    .eventDetail("已验收成果")
                    .eventUrl(todoData.getMinAppUri())
                    .build();
        } else {
            todoData = Todo.builder()
                    .taskId(Convert.toStr(job.getJobId()))
                    .subject(job.getSubject())
                    .reqNumber(job.getTaskNum())
                    .userId(job.getCreateUser())
                    .startTime(DateUtil.now())
                    .status("Current")
                    .nodeName("用户评价")
                    .prvUserId(job.getCreateUser())
                    .prvNickName(getUserNickName(job.getCreateUser()))
                    .prvUserAvatar(getUserAvatar(job.getCreateUser()))
                    .minAppUri("/pages_private_scene1/ExpertCooperate/UserRating?taskNumber=" + dto.getTaskNumber())
                    .build();
            timelineDto = TimelineDto.builder()
                    .userId(dto.getInitiatorId())
                    .ticketNum(dto.getTaskNumber())
                    .eventTitle(retryCount > 0 ? "第" + retryCount + "次返修" : "验收成果")
                    .eventDetail("已验收成果")
                    .build();
        }
        //9、发送时间轴数据
        AsyncManager.me().execute(timelineService.userVerifyResult(timelineDto));
        //10、异步发送小程序消息通知
        AsyncManager.me().execute(sendMsgService.userVerifyResult(msgDto));
        //11、 发送待办给拍档
        return todoService.addToDoData(todoData);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean rejectResult(DeliveryDto dto) {
        //1、更新待办状态
        todoService.updateToDoToDone(dto.getInitiatorId(), dto.getTaskNumber());
        //2、更新返修次数
        Delivery delivery = getById(dto.getDeliveryId());
        int retryCount = Convert.toInt(delivery.getReturnNum()) + 1;
        delivery.setReturnNum(Convert.toStr(retryCount));
        //3、更新验收结果
        List<JSONObject> resultList = JSON.parseArray(delivery.getTaskResultList(), JSONObject.class);
        resultList.forEach(obj -> {
            if (Convert.toInt((obj).getString("sort")) == retryCount) {
                (obj).put("remark", dto.getTmpRemark());
                (obj).put("isEdit", false);
            }
        });
        delivery.setTaskResultList(JSON.toJSONString(resultList));
        updateById(delivery);
        Todo todoData = Todo.builder()
                .taskId(Convert.toStr(delivery.getDeliveryId()))
                .subject(delivery.getWorkSubject())
                .reqNumber(dto.getTaskNumber())
                .userId(dto.getPartnerId())
                .startTime(DateUtil.now())
                .status("Current")
                .nodeName("第" + retryCount + "次返修")
                .prvUserId(dto.getInitiatorId())
                .prvNickName(getUserNickName(dto.getInitiatorId()))
                .prvUserAvatar(getUserAvatar(dto.getInitiatorId()))
                .minAppUri("/pages_private_scene1/ExpertCooperate/partnerDelivery?taskNumber=" + dto.getTaskNumber())
                .build();
        //4、发送时间轴数据
        AsyncManager.me().execute(timelineService.rejectResult(todoData));
        //5、异步发送小程序消息通知
        AsyncManager.me().execute(sendMsgService.rejectResult(MsgDto.builder()
                .userId(dto.getInitiatorId())
                .minAppUri(todoData.getMinAppUri())
                .partnerId(dto.getPartnerId())
                .taskNum(dto.getTaskNumber())
                .deliveryId(delivery.getDeliveryId())
                .build()));
        //6、发送待办给拍档
        return todoService.addToDoData(todoData);
    }

    @Override
    public AjaxResult selectDeliveryDetail(DeliveryDto dto) {
        AjaxResult success = AjaxResult.success();
        Delivery delivery = getById(dto.getDeliveryId());
        success.put("data", delivery);
        List<JSONObject> taskResultList = JSON.parseArray(delivery.getTaskResultList(), JSONObject.class);
        log.info("taskResultList:{}", taskResultList);
        List<JSONObject> resultList = ObjectUtil.isNotNull(taskResultList) ? taskResultList : new ArrayList<>();
        List<JSONObject> resultArray = new ArrayList<>();
        for (JSONObject obj : resultList) {
            JSONObject json = new JSONObject();
            json.put("sort", StrUtil.isBlank(obj.getString("sort")) ? 1 : Convert.toInt(obj.getString("sort")));
            json.put("result", StrUtil.isBlank(obj.getString("result")) ? "-无-" : obj.getString("result"));
            json.put("remark", StrUtil.isBlank(obj.getString("remark")) ? "-无-" : obj.getString("remark"));
            json.put("fileList", StrUtil.isBlank(obj.getString("fileList")) ? new JSONArray() : JSON.parseArray(obj.getString("fileList")));
            json.put("isEdit", StrUtil.isBlank(obj.getString("isEdit")) || Convert.toBool(obj.getString("isEdit")));
            resultArray.add(json);
        }
        if (StrUtil.isNotBlank(dto.getEditTag())) {
            JSONObject obj = new JSONObject();
            obj.put("sort", resultArray.size() + 1);
            obj.put("result", "");
            obj.put("remark", "");
            obj.put("fileList", new JSONArray());
            obj.put("isEdit", true);
            resultArray.add(obj);
        }
        success.put("taskResultList", resultArray);
        return success;
    }


    private TimerTask grantCommission(Delivery delivery) {

        return new TimerTask() {
            @Override
            public void run() {
                String reason = delivery.getWorkSubject() + "项目第" + delivery.getSubTaskSortNum() + "期，佣金发放";
                JSONObject params = new JSONObject();
                params.put("userId", delivery.getPartnerId());
                params.put("coin", delivery.getSubTaskPrice());
                params.put("reason", reason);
                params = getToken(params);
                String uri = getOrderSysTokenUrl.substring(0, getOrderSysTokenUrl.indexOf("points"));
                HttpRequest.post(uri.concat("wallet/recharge"))
                        .header("Content-Type", "application/json")
                        .header("Accept", "application/json")
                        .body(params.toJSONString())
                        .execute();
            }
        };
    }

    public JSONObject getToken(JSONObject object) {
        try {
            HttpResponse resp = HttpRequest.post(getOrderSysTokenUrl)
                    .header("Content-Type", "application/json")
                    .header("Accept", "application/json")
                    .body(object.toJSONString())
                    .execute();
            String token = JSON.parseObject(resp.body()).getString("data");
            String tmpStr = authSalt.charAt(2) + authSalt.charAt(8) + token + authSalt.charAt(10) + authSalt.charAt(5);
            object.put("token", token);
            object.put("authStr", SecureUtil.md5(tmpStr));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return object;
    }

    private String getUserAvatar(String userId) {
        if (ObjectUtil.isNull(userInfo)) {
            userInfo = getUserData(userId);
        }
        return userInfo.getString("avatar");
    }

    private String getUserNickName(String userId) {
        if (ObjectUtil.isNull(userInfo)) {
            userInfo = getUserData(userId);
        }
        return userInfo.getString("nickName");
    }

    private JSONObject getUserData(String userId) {
        JSONObject wxObject = new JSONObject();
        String result = HttpUtil.get(ssoUri + "/user/cache/" + userId);
        if (StrUtil.isNotBlank(result)) {
            wxObject = JSON.parseObject(result);
        }
        return wxObject.getJSONObject("data");
    }
}

